﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace YawetagLib.Linq
{
    internal sealed class Query<TEntity> : IOrderedQueryable<TEntity>
    {
        public Query(IQueryProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }

            Provider = provider;
            Expression = Expression.Constant(this);
        }

        public Query(IQueryProvider provider, Expression expression)
        {
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (!typeof(IQueryable<TEntity>).IsAssignableFrom(expression.Type))
            {
                throw new ArgumentOutOfRangeException("expression");
            }

            Provider = provider;
            Expression = expression;
        }

        public IEnumerator<TEntity> GetEnumerator()
        {
            return Provider.CreateQuery<TEntity>(Expression).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public override string ToString()
        {
            BaseQueryProvider baseQueryProvider = Provider as BaseQueryProvider;

            return baseQueryProvider != null ? baseQueryProvider.GetQueryText(Expression) : Expression.ToString();
        }

        Expression IQueryable.Expression
        {
            get { return Expression; }
        }

        Type IQueryable.ElementType
        {
            get { return typeof(TEntity); }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return Provider; }
        }

        private IQueryProvider Provider { get; set; }
        private Expression Expression { get; set; }
    }
}
